#pragma once
#include <iostream>
#include <jsoncpp/json/json.h>
#include <memory>
// 分隔符空格
const std::string blank_seq = " ";
// 行分隔符
const std::string line_seq = "\n";  // 普通的是\n，telnet为 \r\n

// 注释这个宏，表示使用json的协议，编译时需要链接 jsoncpp 库
#define SelfSerialize 1


namespace Protocol
{

    std::string Encode(const std::string &message)
    {
        // "message" -> "len\nmessage\n"
        std::string len = std::to_string(message.size());
        std::string package = len + line_seq + message + line_seq;
        return package;
    }
    // 循环式处理 字符型字符流数据
    bool Decode(std::string &package, std::string *message)
    {
        // "len\nmessage\n" -> "message"
        // 但是无法保证获取的字节流是完整的报文
        // 1.出现一段残缺的报文 2.收到一段完整的报文和下一段报文拼接 3.恰好收到一段完整的报文

        auto left = package.find(line_seq);
        if (left == std::string::npos) // 未获取message中的长度
            return false;
        // 打包对应的len字段
        std::string len = package.substr(0, left);
        // 总长度为：len字段的长度 + len字段对应的message长度 + 两个换行符
        int length_package = len.size() + std::stoi(len) + 2 * line_seq.size();

        if (length_package > package.size()) // package为情况1
            return false;
        // 获取message并传到外部
        *message = package.substr(left + line_seq.size(), std::stoi(len));
        // 删除完整报文，将剩余部分返回给外部，重新进行Encode
        package.erase(0, length_package);
        return true;
    }

    class Request
    {
    public:
        Request() : _data_x(0), _data_y(0), _oper(0) {}
        Request(int data_x, int data_y, char op)
            : _data_x(data_x), _data_y(data_y), _oper(op) {}

        void Print()
        {
            printf("the request is [%d %c %d]\n", _data_x, _oper, _data_y);
        }
        void Plus()
        {
            _data_x++;
            _data_y++;
        }
        // 结构化数据 转为 字符串形式的字节流
        bool Serialize(std::string *out)
        {
#ifdef SelfSerialize
            // "x op y"
            *out = std::to_string(_data_x) + blank_seq + _oper + blank_seq + std::to_string(_data_y);
            return true;
#else
            // 通过现有的序列化方式
            // 创建value对象
            Json::Value root;
            // 进行kv绑定
            root["data_x"] = _data_x;
            root["data_y"] = _data_y;
            root["oper"] = _oper;
            // 绑定value对象
            Json::FastWriter writer;
            // 输出字符串形式的字节流
            *out = writer.write(root);
#endif
        }
        bool Deserialize(std::string &in)
        {
#ifdef SelfSerialize
            // 截取x
            auto left = in.find(blank_seq);
            if (left == std::string::npos)
                return false;
            _data_x = std::stoi(in.substr(0, left));
            // 截取y
            auto right = in.rfind(blank_seq);
            if (left == right)
                return false;
            _data_y = std::stoi(in.substr(right + blank_seq.size()));
            // 截取oper
            std::string oper = in.substr(left + blank_seq.size(), right - (left + blank_seq.size()));
            if (oper.size() != 1)
                return false;
            _oper = oper[0];
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            // 反序列化成功
            if (reader.parse(in, root) == true)
            {
                std::cout << "json deserialize success " << std::endl;
                _data_x = root["data_x"].asInt();
                _data_y = root["data_y"].asInt();
                _oper = root["oper"].asInt();
                return true;
            }
            return false;

#endif
        }
        int GetX() const { return _data_x; }
        int GetY() const { return _data_y; }
        char GetOper() const { return _oper; }

    private:
        int _data_x;
        int _data_y;
        char _oper; // + - * /
    };

    class Response
    {
    public:
        Response() : _result(0), _code(0) {}
        Response(int result, int code)
            : _result(result), _code(code) {}
        // 结构化数据 转为 字符串形式的字节流
        bool Serialize(std::string *out)
        {
#ifdef SelfSerialize
            // "result code"
            *out = std::to_string(_result) + blank_seq + std::to_string(_code);
            return true;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
#endif
        }
        bool Deserialize(std::string &in)
        {
#ifdef SelfSerialize
            auto left = in.find(blank_seq);
            if (left == std::string::npos)
                return false;
            _result = std::stoi(in.substr(0, left));
            _code = std::stoi(in.substr(left + blank_seq.size()));
            return true;
#else
            Json::Reader reader;
            Json::Value root;
            if (reader.parse(in, root) == true)
            {
                std::cout << "json deserialize success " << std::endl;
                _result = root["result"].asInt();
                _code = root["code"].asInt();
                return true;
            }
            return false;
#endif
        }
        void SetResult(int result) { _result = result; }
        void SetCode(int code) { _code = code; }
        int GetResult() const { return _result; }
        int GetCode() const { return _code; }

    private:
        int _result;
        int _code;
    };

    // 设计模式：工厂模式
    class Factory
    {
    public:
        std::shared_ptr<Request> BuildRequest()
        {
            std::shared_ptr<Request> request = std::make_shared<Request>();
            return request;
        }
        std::shared_ptr<Request> BuildRequest(int data_x, int data_y, char op)
        {
            std::shared_ptr<Request> request = std::make_shared<Request>(data_x, data_y, op);
            return request;
        }
        std::shared_ptr<Response> BuildResponse()
        {
            std::shared_ptr<Response> response = std::make_shared<Response>();
            return response;
        }
        std::shared_ptr<Response> BuildResponse(int result, int code)
        {
            std::shared_ptr<Response> response = std::make_shared<Response>(result, code);
            return response;
        }

    private:
    };
}